/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package org.epsi.blokus.salon;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ConnectException;
import java.net.Socket;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Observable;
import java.util.Stack;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JOptionPane;
import org.epsi.blokus.Hex;
import org.epsi.blokus.commun.Message;
import org.epsi.blokus.tools.IConstantes;


/**
 * Gestion de la connexion avec le serveur
 * @author julien.lafont
 */
public class ServerClient extends Observable implements Runnable, IConstantes  {

    // Gestion liaison serveur
    private Socket socket = null;
    private ObjectOutputStream out = null;
    private ObjectInputStream in = null;

    private GuiSalon gui;

    public ServerClient()
    {
        try {

            String ip = JOptionPane.showInputDialog(null, "Entrez l'adresse du serveur", "127.0.0.1");

            // Ouverture de la socket et des flux
            socket = new Socket(ip, PORT_SERVER);
            out = new ObjectOutputStream(socket.getOutputStream());
            in = new ObjectInputStream(socket.getInputStream());

            // Cré le GUI
            gui = new GuiSalon(this);
            gui.setVisible(true);
            this.addObserver(gui);

            // On avise le serveur de la connexion cu client
            Message m = new Message();
            m.setTypeMessage(Message.TTypeMessage.connexion_client);
            this.envoyer(m);

            // Lance l'écoute
            Thread t = new Thread(this);
            t.start();

            /*for (int i=0; i < 3; i++)
            for(Message.TTypeMessage type : Message.TTypeMessage.values())
            {
                System.out.println("> Envoie du message : "+type);
                Message m2 = new Message(type);
                this.envoyer(m2);

                try {
                    Thread.sleep(500);
                } catch (InterruptedException ex) {
                    Logger.getLogger(ServerClient.class.getName()).log(Level.SEVERE, null, ex);
                }
            }*/


        } catch(ConnectException ex) {
            if ( JOptionPane.showConfirmDialog(null, "Le serveur ne répond pas.\nSouhaitez vous lancer une partie d'entrainement ?", "Hex", JOptionPane.YES_NO_OPTION) == JOptionPane.YES_OPTION)
            {
                Hex.getInstance().newTrainingGame();
            }
            
        } catch (UnknownHostException ex) {
            JOptionPane.showMessageDialog(null, "Impossible de retrouver le serveur");
        } catch (IOException ex) {
            JOptionPane.showMessageDialog(null, "Impossible d'établir la liaison avec le serveur");
        }
        
    }

    
    // Initialise une fenêtre de création de salon
    public void creationSalon(){
      CreateSalon creerSalon   = new CreateSalon(this);
      creerSalon.setVisible(true);
    }


    private Boolean ecoute = true;

    /**
     * Thread d'écoute
     */
    public  void run() {

        try {

            Stack<Message> pileMessage  = new Stack<Message>();
            
            // Boucle principale du ServeurClient : tourne tant qu'aucun message d'arrêt n'a été recu
            // et tant qu'aucune erreur n'est survenue.
            while(ecoute)
            {
                 Message mess;
                 while (ecoute && (pileMessage.add((Message)in.readObject())))
                 {

                    //System.out.println("< Réception du message : "+mess.getTypeMessage());
                     
                    // On notifie le GUI du message reçu
                    setChanged();
                    notifyObservers(pileMessage.pop().clone());
                    clearChanged();

                    System.out.println("Fin");

                    
                    //if (mess.getTypeMessage() == Message.TTypeMessage.deconnexion_client) ecoute = false;
                 }

                 ecoute = false;
            }

         // Le serveur a rompu la communication
         } catch (SocketException ex) {
            JOptionPane.showMessageDialog(null, "Le serveur ne répond plus.\nFermeture de la connexion.", "Erreur", JOptionPane.ERROR_MESSAGE);
            System.exit(-1);
            
         // Une erreur de communication équivaut à la déconnexion du client
         } catch (Exception ex) {
            ecoute = false;

            // On indique au serveur que le client est déconnecté
            setChanged();
            notifyObservers(new Message(Message.TTypeMessage.deconnexion_client));

        // Fermer toutes les connexions à la fin du thread
        } finally {

            // Fermeture de la socket
            forcerFermetureSocket();
        }
    }


    /**
     * Ferme la socket correctement
     */
    private void forcerFermetureSocket()
    {
        try {
            if(in!=null)        in.close();
            if (out!=null)      out.close();
            if (socket!=null)   socket.close();

        } catch(IOException exNonTraitee) {}
    }


    /**
     * Envoyer un message au client
     * @param m
     * @return
     */
    public synchronized  Boolean envoyer(Message m)
    {
        try {
            this.out.writeObject(m);
            return true;
        } catch(Exception e) {
            return false;
        }
    }

}
